from django.db import models
from django.contrib.auth.models import User

# 导入标签相关模型
from .models_label import LabelTemplate, LabelPrintHistory
# 导入软件管理相关模型（放在此处以确保被Django加载）
from .models_software import *  # noqa: F401,F403

class Organization(models.Model):
    """组织模型"""
    name = models.CharField(max_length=100, unique=True, verbose_name="组织名称")
    code = models.CharField(max_length=50, unique=True, verbose_name="组织代码")
    description = models.TextField(blank=True, verbose_name="描述")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "组织"
        verbose_name_plural = "组织"
    
    def __str__(self):
        return self.name


class Location(models.Model):
    """位置信息模型"""
    name = models.CharField(max_length=100, verbose_name="位置名称")
    address = models.TextField(blank=True, verbose_name="详细地址")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "位置"
        verbose_name_plural = "位置"
    
    def __str__(self):
        return self.name


class Department(models.Model):
    """部门模型"""
    name = models.CharField(max_length=100, verbose_name="部门名称")
    code = models.CharField(max_length=50, verbose_name="部门代码")
    organization = models.ForeignKey(Organization, on_delete=models.CASCADE, verbose_name="所属组织")
    location = models.ForeignKey(Location, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="位置")
    parent = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, verbose_name="上级部门")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "部门"
        verbose_name_plural = "部门"
    
    def __str__(self):
        return self.name


class AssetLedger(models.Model):
    """资产账簿/财务组织模型：用于对资产进行账簿维度的分账管理"""
    name = models.CharField(max_length=100, verbose_name="账簿名称")
    code = models.CharField(max_length=50, verbose_name="账簿代码")
    organization = models.ForeignKey(Organization, on_delete=models.CASCADE, verbose_name="所属组织", related_name='ledgers')
    description = models.TextField(blank=True, verbose_name="备注")
    active = models.BooleanField(default=True, verbose_name="是否启用")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")

    class Meta:
        verbose_name = "资产账簿"
        verbose_name_plural = "资产账簿"
        unique_together = (
            ('organization', 'code'),
            ('organization', 'name'),
        )

    def __str__(self):
        return f"{self.organization.name} / {self.name}"


class UserProfile(models.Model):
    """用户扩展信息"""
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
    employee_id = models.CharField(max_length=50, unique=True, verbose_name="员工编号")
    department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="所属部门")
    phone = models.CharField(max_length=20, blank=True, verbose_name="联系电话")
    # 访问范围：可访问的组织与账簿（组合生效：拥有任一账簿或其所属组织即有访问权限）
    allowed_organizations = models.ManyToManyField('Organization', blank=True, related_name='permitted_users', verbose_name="可访问组织")
    allowed_ledgers = models.ManyToManyField('AssetLedger', blank=True, related_name='permitted_users', verbose_name="可访问账簿")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "用户资料"
        verbose_name_plural = "用户资料"
    
    def __str__(self):
        return f"{self.user.username} - {self.employee_id}"


class AssetCategory(models.Model):
    """资产类别模型"""
    name = models.CharField(max_length=100, unique=True, verbose_name="类别名称")
    code = models.CharField(max_length=50, unique=True, verbose_name="类别代码")
    description = models.TextField(blank=True, verbose_name="描述")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "资产类别"
        verbose_name_plural = "资产类别"
    
    def __str__(self):
        return self.name


class Supplier(models.Model):
    """供应商模型"""
    SUPPLIER_TYPE_CHOICES = [
        ('enterprise', '企业'),
        ('individual', '个体工商户'),
        ('institution', '事业单位'),
        ('government', '政府机构'),
        ('other', '其他'),
    ]
    
    # 基本信息
    name = models.CharField(max_length=200, verbose_name="供应商名称")
    supplier_type = models.CharField(max_length=20, choices=SUPPLIER_TYPE_CHOICES, default='enterprise', verbose_name="供应商类型")
    credit_code = models.CharField(max_length=50, blank=True, verbose_name="统一社会信用代码")
    legal_representative = models.CharField(max_length=100, blank=True, verbose_name="法定代表人")
    registration_address = models.TextField(blank=True, verbose_name="注册地址")
    business_scope = models.TextField(blank=True, verbose_name="经营范围")
    
    # 联系信息
    contact_person = models.CharField(max_length=100, blank=True, verbose_name="联系人")
    contact_position = models.CharField(max_length=100, blank=True, verbose_name="联系人职位")
    phone = models.CharField(max_length=20, blank=True, verbose_name="联系电话")
    mobile = models.CharField(max_length=20, blank=True, verbose_name="手机号码")
    fax = models.CharField(max_length=20, blank=True, verbose_name="传真号码")
    email = models.EmailField(blank=True, verbose_name="邮箱")
    website = models.URLField(blank=True, verbose_name="官方网站")
    address = models.TextField(blank=True, verbose_name="联系地址")
    postal_code = models.CharField(max_length=10, blank=True, verbose_name="邮政编码")
    
    # 银行信息
    bank_name = models.CharField(max_length=200, blank=True, verbose_name="开户银行")
    bank_account = models.CharField(max_length=50, blank=True, verbose_name="银行账号")
    bank_address = models.CharField(max_length=200, blank=True, verbose_name="开户行地址")
    
    # 营业执照
    business_license = models.FileField(upload_to='suppliers/licenses/', blank=True, null=True, verbose_name="营业执照")
    
    # 备注信息
    description = models.TextField(blank=True, verbose_name="备注说明")
    
    # 评价与信用信息
    credit_rating = models.CharField(
        max_length=10, 
        choices=[
            ('AAA', 'AAA级'),
            ('AA', 'AA级'),
            ('A', 'A级'),
            ('BBB', 'BBB级'),
            ('BB', 'BB级'),
            ('B', 'B级'),
            ('CCC', 'CCC级'),
            ('CC', 'CC级'),
            ('C', 'C级'),
            ('D', 'D级'),
        ],
        blank=True,
        verbose_name="信用等级"
    )
    service_rating = models.DecimalField(
        max_digits=3, 
        decimal_places=1, 
        blank=True, 
        null=True,
        verbose_name="服务评分",
        help_text="1-5分"
    )
    quality_rating = models.DecimalField(
        max_digits=3, 
        decimal_places=1, 
        blank=True, 
        null=True,
        verbose_name="质量评分",
        help_text="1-5分"
    )
    delivery_rating = models.DecimalField(
        max_digits=3, 
        decimal_places=1, 
        blank=True, 
        null=True,
        verbose_name="交付评分",
        help_text="1-5分"
    )
    cooperation_count = models.PositiveIntegerField(default=0, verbose_name="合作次数")
    last_cooperation_date = models.DateField(blank=True, null=True, verbose_name="最后合作日期")
    is_preferred = models.BooleanField(default=False, verbose_name="优选供应商")
    is_blacklisted = models.BooleanField(default=False, verbose_name="黑名单")
    blacklist_reason = models.TextField(blank=True, verbose_name="黑名单原因")
    
    # 时间戳
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "供应商"
        verbose_name_plural = "供应商"
    
    def __str__(self):
        return self.name
    
    def get_business_license_url(self):
        """获取营业执照URL"""
        if self.business_license:
            return self.business_license.url
        return None
    
    def get_overall_rating(self):
        """计算综合评分"""
        ratings = [self.service_rating, self.quality_rating, self.delivery_rating]
        valid_ratings = [r for r in ratings if r is not None]
        if valid_ratings:
            return round(sum(valid_ratings) / len(valid_ratings), 1)
        return None
    
    def get_rating_stars(self, rating=None):
        """获取评分星级显示"""
        if rating is None:
            rating = self.get_overall_rating()
        if rating is None:
            return "未评分"
        
        full_stars = int(rating)
        half_star = 1 if rating - full_stars >= 0.5 else 0
        empty_stars = 5 - full_stars - half_star
        
        stars = "★" * full_stars + "☆" * half_star + "☆" * empty_stars
        return f"{stars} ({rating})"
    
    def get_credit_rating_color(self):
        """获取信用等级颜色"""
        color_map = {
            'AAA': 'success',
            'AA': 'success', 
            'A': 'info',
            'BBB': 'info',
            'BB': 'warning',
            'B': 'warning',
            'CCC': 'danger',
            'CC': 'danger',
            'C': 'danger',
            'D': 'dark',
        }
        return color_map.get(self.credit_rating, 'secondary')
    
    def get_status_display(self):
        """获取供应商状态显示"""
        if self.is_blacklisted:
            return "黑名单"
        elif self.is_preferred:
            return "优选供应商"
        else:
            return "普通供应商"
    
    def get_status_color(self):
        """获取供应商状态颜色"""
        if self.is_blacklisted:
            return "danger"
        elif self.is_preferred:
            return "success"
        else:
            return "primary"


class SupplierDocument(models.Model):
    """供应商资质文件模型"""
    DOCUMENT_TYPE_CHOICES = [
        ('qualification', '资质证书'),
        ('certificate', '认证证书'),
        ('permit', '许可证'),
        ('tax', '税务登记证'),
        ('organization', '组织机构代码证'),
        ('other', '其他文件'),
    ]
    
    supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE, verbose_name="供应商", related_name='documents')
    document_type = models.CharField(max_length=20, choices=DOCUMENT_TYPE_CHOICES, verbose_name="文件类型")
    title = models.CharField(max_length=200, verbose_name="文件标题")
    file = models.FileField(upload_to='suppliers/documents/', verbose_name="文件")
    description = models.TextField(blank=True, verbose_name="文件描述")
    expiry_date = models.DateField(blank=True, null=True, verbose_name="有效期至")
    
    uploaded_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="上传人")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="上传时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "供应商文件"
        verbose_name_plural = "供应商文件"
        ordering = ['-created_at']
    
    def __str__(self):
        return f"{self.supplier.name} - {self.title}"
    
    def get_file_url(self):
        """获取文件URL"""
        if self.file:
            return self.file.url
        return None
    
    def get_file_size(self):
        """获取文件大小（MB）"""
        if self.file and hasattr(self.file, 'size'):
            return round(self.file.size / (1024 * 1024), 2)
        return 0
    
    def get_file_extension(self):
        """获取文件扩展名"""
        if self.file and self.file.name:
            return self.file.name.split('.')[-1].lower()
        return ''
    
    def get_file_icon(self):
        """根据文件类型获取图标"""
        extension = self.get_file_extension()
        icons = {
            'pdf': 'fa-file-pdf',
            'doc': 'fa-file-word',
            'docx': 'fa-file-word',
            'xls': 'fa-file-excel',
            'xlsx': 'fa-file-excel',
            'jpg': 'fa-file-image',
            'jpeg': 'fa-file-image',
            'png': 'fa-file-image',
            'gif': 'fa-file-image',
            'txt': 'fa-file-text',
        }
        return icons.get(extension, 'fa-file')
    
    def is_expired(self):
        """检查文件是否已过期"""
        if self.expiry_date:
            from django.utils import timezone
            return self.expiry_date < timezone.now().date()
        return False
    
    def delete(self, *args, **kwargs):
        """删除时清理文件"""
        if self.file:
            try:
                self.file.delete(save=False)
            except Exception:
                pass  # 文件可能已经不存在
        super().delete(*args, **kwargs)


class Contract(models.Model):
    """合同模型"""
    CONTRACT_STATUS_CHOICES = [
        ('draft', '草稿'),
        ('active', '生效中'),
        ('expired', '已过期'),
        ('terminated', '已终止'),
    ]
    
    CONTRACT_TYPE_CHOICES = [
        ('purchase', '采购合同'),
        ('service', '服务合同'),
        ('lease', '租赁合同'),
        ('maintenance', '维护合同'),
        ('other', '其他合同'),
    ]
    
    # 基本信息
    name = models.CharField(max_length=200, verbose_name="合同名称")
    contract_number = models.CharField(max_length=100, unique=True, verbose_name="合同编号")
    contract_type = models.CharField(max_length=20, choices=CONTRACT_TYPE_CHOICES, default='purchase', verbose_name="合同类型")
    supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE, verbose_name="供应商")
    
    # 合同期限与金额
    signed_date = models.DateField(null=True, blank=True, verbose_name="签订日期")
    effective_date = models.DateField(null=True, blank=True, verbose_name="生效日期")
    start_date = models.DateField(verbose_name="开始日期")
    end_date = models.DateField(verbose_name="结束日期")
    amount = models.DecimalField(max_digits=15, decimal_places=2, verbose_name="合同金额")
    
    # 合同双方信息
    our_company_name = models.CharField(max_length=200, blank=True, verbose_name="我方公司名称")
    our_company_address = models.TextField(blank=True, verbose_name="我方公司地址")
    our_signatory = models.CharField(max_length=100, blank=True, verbose_name="我方签约人")
    our_signatory_title = models.CharField(max_length=100, blank=True, verbose_name="我方签约人职务")
    
    their_company_name = models.CharField(max_length=200, blank=True, verbose_name="对方公司名称")
    their_company_address = models.TextField(blank=True, verbose_name="对方公司地址")
    their_signatory = models.CharField(max_length=100, blank=True, verbose_name="对方签约人")
    their_signatory_title = models.CharField(max_length=100, blank=True, verbose_name="对方签约人职务")
    
    # 合同条款摘要
    main_subject = models.TextField(blank=True, verbose_name="主要标的物")
    delivery_requirements = models.TextField(blank=True, verbose_name="交付要求")
    special_terms = models.TextField(blank=True, verbose_name="特殊条款")
    
    # 状态和审核
    status = models.CharField(max_length=20, choices=CONTRACT_STATUS_CHOICES, default='draft', verbose_name="合同状态")
    created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='created_contracts', verbose_name="创建人")
    reviewed_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='reviewed_contracts', verbose_name="审核人")
    reviewed_at = models.DateTimeField(null=True, blank=True, verbose_name="审核时间")
    review_notes = models.TextField(blank=True, verbose_name="审核备注")
    
    # 其他信息
    description = models.TextField(blank=True, verbose_name="描述")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "合同"
        verbose_name_plural = "合同"
        ordering = ['-created_at']
    
    def __str__(self):
        return self.name
    
    @property
    def is_active(self):
        """判断合同是否生效"""
        from django.utils import timezone
        today = timezone.now().date()
        return (self.status == 'active' and 
                self.start_date <= today <= self.end_date)
    
    @property
    def days_remaining(self):
        """计算合同剩余天数"""
        from django.utils import timezone
        if self.status == 'active':
            today = timezone.now().date()
            if today <= self.end_date:
                return (self.end_date - today).days
        return 0
    
    @property
    def main_contract_file(self):
        """获取主合同文件"""
        return self.files.filter(file_type='main').first()


class ContractFile(models.Model):
    """合同文件模型"""
    FILE_TYPE_CHOICES = [
        ('main', '主合同文件'),
        ('attachment', '合同附件'),
        ('amendment', '合同修订'),
        ('other', '其他文件'),
    ]
    
    contract = models.ForeignKey(Contract, on_delete=models.CASCADE, related_name='files', verbose_name="关联合同")
    file_type = models.CharField(max_length=20, choices=FILE_TYPE_CHOICES, default='attachment', verbose_name="文件类型")
    file_name = models.CharField(max_length=255, verbose_name="文件名称")
    file_path = models.FileField(upload_to='contracts/%Y/%m/', verbose_name="文件路径")
    file_size = models.PositiveIntegerField(default=0, verbose_name="文件大小(字节)")
    description = models.TextField(blank=True, verbose_name="文件描述")
    uploaded_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="上传人")
    uploaded_at = models.DateTimeField(auto_now_add=True, verbose_name="上传时间")
    
    class Meta:
        verbose_name = "合同文件"
        verbose_name_plural = "合同文件"
        ordering = ['-uploaded_at']
    
    def __str__(self):
        return f"{self.contract.name} - {self.file_name}"
    
    @property
    def file_size_mb(self):
        """文件大小(MB)"""
        return round(self.file_size / (1024 * 1024), 2)


class ContractReview(models.Model):
    """合同审核记录模型"""
    REVIEW_TYPE_CHOICES = [
        ('submit', '提交审核'),
        ('approve', '审核通过'),
        ('reject', '审核拒绝'),
        ('return', '退回修改'),
    ]
    
    contract = models.ForeignKey(Contract, on_delete=models.CASCADE, related_name='reviews', verbose_name="关联合同")
    review_type = models.CharField(max_length=20, choices=REVIEW_TYPE_CHOICES, verbose_name="审核类型")
    reviewer = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="审核人")
    review_notes = models.TextField(blank=True, verbose_name="审核意见")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="审核时间")
    
    class Meta:
        verbose_name = "合同审核记录"
        verbose_name_plural = "合同审核记录"
        ordering = ['-created_at']
    
    def __str__(self):
        return f"{self.contract.name} - {self.get_review_type_display()}"


class Asset(models.Model):
    """核心资产模型"""
    ASSET_STATUS_CHOICES = [
        ('idle', '闲置'),
        ('in_use', '在用'),
        ('borrowed', '已借出'),
        ('maintenance', '维修中'),
        ('faulty', '故障'),
        ('scrapped', '已报废'),
    ]
    
    name = models.CharField(max_length=200, verbose_name="资产名称")
    asset_number = models.CharField(max_length=100, unique=True, verbose_name="资产编号")
    category = models.ForeignKey(AssetCategory, on_delete=models.CASCADE, verbose_name="资产类别")
    department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="所属部门")
    user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="使用人")
    location = models.ForeignKey(Location, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="位置")
    supplier = models.ForeignKey(Supplier, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="供应商")
    contract = models.ForeignKey(Contract, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="合同")
    # 新增：账簿归属
    ledger = models.ForeignKey('AssetLedger', on_delete=models.PROTECT, null=True, blank=True, verbose_name="所属账簿", related_name='assets')
    
    # 财务信息
    purchase_date = models.DateField(verbose_name="采购日期")
    purchase_price = models.DecimalField(max_digits=15, decimal_places=2, verbose_name="采购价格")
    warranty_period = models.IntegerField(verbose_name="保修期(月)", default=0)
    depreciation_rate = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="折旧率(%)", default=0)
    
    # 状态信息
    status = models.CharField(max_length=20, choices=ASSET_STATUS_CHOICES, default='idle', verbose_name="资产状态")
    description = models.TextField(blank=True, verbose_name="描述")
    
    # 扩展信息
    qr_code = models.ImageField(upload_to='assets/qrcodes/', blank=True, null=True, verbose_name="二维码")
    image = models.ImageField(upload_to='assets/images/', blank=True, null=True, verbose_name="资产图片")
    
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "资产"
        verbose_name_plural = "资产"
    
    def __str__(self):
        return f"{self.name} ({self.asset_number})"
    
    @property
    def current_value(self):
        """计算资产当前价值（考虑折旧）"""
        from django.utils import timezone
        from decimal import Decimal
        import datetime
        
        if not self.purchase_date or not self.purchase_price:
            return self.purchase_price or Decimal('0')
        
        # 计算使用年限
        current_date = timezone.now().date()
        years_used = (current_date - self.purchase_date).days / 365.25
        
        if self.depreciation_rate > 0:
            # 直线折旧法
            annual_depreciation = self.purchase_price * (self.depreciation_rate / 100)
            total_depreciation = Decimal(str(annual_depreciation)) * Decimal(str(years_used))
            current_value = self.purchase_price - total_depreciation
            
            # 确保不会低于0
            return max(current_value, Decimal('0'))
        
        return self.purchase_price
    
    @property
    def depreciation_amount(self):
        """计算已折旧金额"""
        return self.purchase_price - self.current_value if self.purchase_price else Decimal('0')
    
    @property
    def depreciation_percentage(self):
        """计算折旧百分比"""
        if not self.purchase_price or self.purchase_price == 0:
            return 0
        return float((self.depreciation_amount / self.purchase_price) * 100)
    
    @property
    def remaining_useful_life(self):
        """计算剩余使用年限（基于折旧率）"""
        if self.depreciation_rate <= 0:
            return None
        
        # 假设资产在折旧率为100%时完全折旧
        total_useful_life = 100 / self.depreciation_rate  # 年
        
        from django.utils import timezone
        current_date = timezone.now().date()
        years_used = (current_date - self.purchase_date).days / 365.25
        
        remaining = total_useful_life - years_used
        return max(remaining, 0)
    
    @property
    def is_fully_depreciated(self):
        """判断资产是否已完全折旧"""
        return self.current_value <= 0
    
    def calculate_depreciation_schedule(self, years=None):
        """计算折旧计划表"""
        from decimal import Decimal
        import datetime
        
        if not self.purchase_date or not self.purchase_price or self.depreciation_rate <= 0:
            return []
        
        if years is None:
            years = min(int(100 / self.depreciation_rate), 20)  # 最多20年
        
        schedule = []
        annual_depreciation = self.purchase_price * (self.depreciation_rate / 100)
        remaining_value = self.purchase_price
        
        for year in range(1, years + 1):
            year_date = self.purchase_date + datetime.timedelta(days=int(365.25 * year))
            depreciation_amount = min(annual_depreciation, remaining_value)
            remaining_value -= depreciation_amount
            
            schedule.append({
                'year': year,
                'date': year_date,
                'depreciation_amount': depreciation_amount,
                'remaining_value': max(remaining_value, Decimal('0')),
                'accumulated_depreciation': self.purchase_price - max(remaining_value, Decimal('0'))
            })
            
            if remaining_value <= 0:
                break
        
        return schedule
    
    def generate_qr_code(self):
        """生成资产二维码"""
        import qrcode
        from io import BytesIO
        from django.core.files import File
        from django.conf import settings
        import os
        
        # 创建二维码内容（包含资产基本信息）
        qr_data = {
            'asset_number': self.asset_number,
            'name': self.name,
            'category': self.category.name if self.category else '',
            'department': self.department.name if self.department else '',
            'url': f"{settings.SITE_URL}/assets/asset/{self.id}/" if hasattr(settings, 'SITE_URL') else f"/assets/asset/{self.id}/"
        }
        
        # 将数据转为JSON字符串
        import json
        qr_content = json.dumps(qr_data, ensure_ascii=False)
        
        # 生成二维码
        qr = qrcode.QRCode(
            version=1,
            error_correction=qrcode.constants.ERROR_CORRECT_L,
            box_size=10,
            border=4,
        )
        qr.add_data(qr_content)
        qr.make(fit=True)
        
        # 创建二维码图像
        qr_img = qr.make_image(fill_color="black", back_color="white")
        
        # 保存到内存
        buffer = BytesIO()
        qr_img.save(buffer, format='PNG')
        buffer.seek(0)
        
        # 保存到模型字段
        filename = f"qr_{self.asset_number}.png"
        self.qr_code.save(filename, File(buffer), save=False)
        buffer.close()
        
        return self.qr_code
    
    def get_qr_code_url(self):
        """获取二维码URL"""
        if self.qr_code:
            return self.qr_code.url
        return None
    
    def get_image_url(self):
        """获取资产图片URL"""
        if self.image:
            return self.image.url
        return None
    
    def get_all_images(self):
        """获取所有关联图片"""
        images = []
        if self.image:
            images.append({
                'url': self.image.url,
                'is_primary': True,
                'title': '主图片',
                'id': 'main',
                'type': 'main'
            })
        
        # 获取额外图片
        for img in self.asset_images.all():
            images.append({
                'url': img.image.url,
                'is_primary': img.is_primary,
                'title': img.title or f'图片{img.id}',
                'description': img.description,
                'id': img.id,
                'type': 'additional',
                'file_size': img.get_file_size(),
                'uploaded_by': img.uploaded_by.username if img.uploaded_by else '',
                'created_at': img.created_at
            })
        
        return images
    
    def get_all_files(self):
        """获取所有关联文件"""
        files = []
        for file in self.asset_files.all():
            files.append({
                'url': file.get_file_url(),
                'title': file.title,
                'description': file.description,
                'id': file.id,
                'file_type': file.file_type,
                'file_size': file.get_file_size_display(),
                'file_icon': file.get_file_icon(),
                'uploaded_by': file.uploaded_by.username if file.uploaded_by else '',
                'created_at': file.created_at
            })
        
        return files
    
    def get_image_count(self):
        """获取图片总数"""
        count = 0
        if self.image:
            count += 1
        count += self.asset_images.count()
        return count
    
    def get_file_count(self):
        """获取文件总数"""
        return self.asset_files.count()
    
    def can_add_more_images(self, max_images=10):
        """检查是否可以添加更多图片"""
        return self.get_image_count() < max_images
    
    def can_add_more_files(self, max_files=20):
        """检查是否可以添加更多文件"""
        return self.get_file_count() < max_files
    
    def get_primary_image_url(self):
        """获取主要图片URL（优先返回主图片，然后返回第一张图片）"""
        if self.image:
            return self.image.url
        
        first_image = self.asset_images.first()
        if first_image:
            return first_image.image.url
        
        return None
    
    def save(self, *args, **kwargs):
        """重写save方法，自动生成二维码"""
        is_new = self.pk is None
        super().save(*args, **kwargs)
        
        # 如果是新资产或者没有二维码，则生成二维码
        if is_new or not self.qr_code:
            try:
                self.generate_qr_code()
                # 再次保存以更新二维码字段
                super().save(update_fields=['qr_code'])
            except Exception as e:
                # 如果二维码生成失败，记录日志但不影响保存
                import logging
                logger = logging.getLogger(__name__)
                logger.warning(f"资产 {self.asset_number} 二维码生成失败: {e}")


class AssetImage(models.Model):
    """资产图片模型"""
    asset = models.ForeignKey(Asset, on_delete=models.CASCADE, verbose_name="资产", related_name='asset_images')
    image = models.ImageField(upload_to='assets/images/', verbose_name="图片")
    title = models.CharField(max_length=200, blank=True, verbose_name="标题")
    description = models.TextField(blank=True, verbose_name="描述")
    is_primary = models.BooleanField(default=False, verbose_name="主图片")
    sort_order = models.IntegerField(default=0, verbose_name="排序")
    
    uploaded_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="上传人")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="上传时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "资产图片"
        verbose_name_plural = "资产图片"
        ordering = ['sort_order', 'created_at']
    
    def __str__(self):
        return f"{self.asset.name} - {self.title or '图片'}"
    
    def get_image_url(self):
        """获取图片URL"""
        if self.image:
            return self.image.url
        return None
    
    def get_thumbnail_url(self, size='300x300'):
        """获取缩略图URL（这里可以扩展实现真正的缩略图）"""
        return self.get_image_url()
    
    def get_file_size(self):
        """获取文件大小（MB）"""
        if self.image and hasattr(self.image, 'size'):
            return round(self.image.size / (1024 * 1024), 2)
        return 0
    
    def save(self, *args, **kwargs):
        """保存时自动处理主图片设置"""
        # 如果设置为主图片，则取消其他主图片
        if self.is_primary:
            AssetImage.objects.filter(
                asset=self.asset, 
                is_primary=True
            ).exclude(id=self.id).update(is_primary=False)
        
        super().save(*args, **kwargs)
    
    def delete(self, *args, **kwargs):
        """删除时清理文件"""
        if self.image:
            try:
                self.image.delete(save=False)
            except Exception:
                pass  # 文件可能已经不存在
        super().delete(*args, **kwargs)


class AssetFile(models.Model):
    """资产文件模型（支持PDF等文档）"""
    FILE_TYPE_CHOICES = [
        ('pdf', 'PDF文档'),
        ('doc', 'Word文档'),
        ('docx', 'Word文档'),
        ('xls', 'Excel表格'),
        ('xlsx', 'Excel表格'),
        ('txt', '文本文件'),
        ('other', '其他'),
    ]
    
    asset = models.ForeignKey(Asset, on_delete=models.CASCADE, verbose_name="资产", related_name='asset_files')
    file = models.FileField(upload_to='assets/files/', verbose_name="文件")
    title = models.CharField(max_length=200, verbose_name="文件标题")
    description = models.TextField(blank=True, verbose_name="文件描述")
    file_type = models.CharField(max_length=10, choices=FILE_TYPE_CHOICES, verbose_name="文件类型")
    file_size = models.PositiveIntegerField(default=0, verbose_name="文件大小(字节)")
    sort_order = models.IntegerField(default=0, verbose_name="排序")
    
    uploaded_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="上传人")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="上传时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "资产文件"
        verbose_name_plural = "资产文件"
        ordering = ['sort_order', 'created_at']
    
    def __str__(self):
        return f"{self.asset.name} - {self.title}"
    
    def get_file_url(self):
        """获取文件URL"""
        if self.file:
            return self.file.url
        return None
    
    def get_file_size_display(self):
        """获取文件大小显示"""
        if self.file_size:
            if self.file_size < 1024:
                return f"{self.file_size} B"
            elif self.file_size < 1024 * 1024:
                return f"{round(self.file_size / 1024, 1)} KB"
            else:
                return f"{round(self.file_size / (1024 * 1024), 1)} MB"
        return "未知"
    
    def get_file_extension(self):
        """获取文件扩展名"""
        if self.file and self.file.name:
            return self.file.name.split('.')[-1].lower()
        return ''
    
    def get_file_icon(self):
        """根据文件类型获取图标"""
        icons = {
            'pdf': 'fa-file-pdf',
            'doc': 'fa-file-word',
            'docx': 'fa-file-word',
            'xls': 'fa-file-excel',
            'xlsx': 'fa-file-excel',
            'txt': 'fa-file-text',
        }
        return icons.get(self.file_type, 'fa-file')
    
    def save(self, *args, **kwargs):
        """保存时自动设置文件类型和大小"""
        if self.file:
            # 自动设置文件大小
            if hasattr(self.file, 'size'):
                self.file_size = self.file.size
            
            # 自动设置文件类型
            if not self.file_type or self.file_type == 'other':
                extension = self.get_file_extension()
                if extension in ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'txt']:
                    self.file_type = extension
                else:
                    self.file_type = 'other'
        
        super().save(*args, **kwargs)
    
    def delete(self, *args, **kwargs):
        """删除时清理文件"""
        if self.file:
            try:
                self.file.delete(save=False)
            except Exception:
                pass  # 文件可能已经不存在
        super().delete(*args, **kwargs)


class AssetLog(models.Model):
    """资产操作日志模型"""
    ACTION_CHOICES = [
        ('create', '创建'),
        ('update', '更新'),
        ('allocate', '分配'),
        ('transfer', '转移'),
        ('maintenance', '维修'),
        ('scrap', '报废'),
        ('image_upload', '图片上传'),
        ('image_delete', '图片删除'),
        ('borrow', '借用'),
        ('return', '归还'),
        ('inventory', '盘点'),
        ('qr_generate', '二维码生成'),
        ('label_print', '标签打印'),
        ('status_change', '状态变更'),
        ('location_change', '位置变更'),
        ('user_change', '使用人变更'),
        ('department_change', '部门变更'),
    ]
    
    asset = models.ForeignKey(Asset, on_delete=models.CASCADE, verbose_name="资产", related_name='logs')
    action = models.CharField(max_length=20, choices=ACTION_CHOICES, verbose_name="操作类型")
    operator = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, verbose_name="操作人")
    description = models.TextField(verbose_name="操作描述")
    
    # 详细信息字段
    old_value = models.JSONField(blank=True, null=True, verbose_name="变更前值")
    new_value = models.JSONField(blank=True, null=True, verbose_name="变更后值")
    ip_address = models.GenericIPAddressField(blank=True, null=True, verbose_name="IP地址")
    user_agent = models.TextField(blank=True, verbose_name="用户代理")
    
    # 关联信息
    related_object_type = models.CharField(max_length=50, blank=True, verbose_name="关联对象类型")
    related_object_id = models.PositiveIntegerField(blank=True, null=True, verbose_name="关联对象ID")
    
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="操作时间")
    # 软删除标记
    is_deleted = models.BooleanField(default=False, verbose_name="是否已删除")
    
    class Meta:
        verbose_name = "资产日志"
        verbose_name_plural = "资产日志"
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['asset', '-created_at']),
            models.Index(fields=['operator', '-created_at']),
            models.Index(fields=['action', '-created_at']),
        ]
    
    def __str__(self):
        return f"{self.asset.asset_number} - {self.get_action_display()}"
    
    @classmethod
    def log_action(cls, asset, action, operator, description, old_value=None, new_value=None, request=None, related_object=None):
        """记录操作日志的便捷方法"""
        log_data = {
            'asset': asset,
            'action': action,
            'operator': operator,
            'description': description,
            'old_value': old_value,
            'new_value': new_value,
        }
        
        if request:
            log_data['ip_address'] = cls.get_client_ip(request)
            log_data['user_agent'] = request.META.get('HTTP_USER_AGENT', '')
        
        if related_object:
            log_data['related_object_type'] = related_object.__class__.__name__
            log_data['related_object_id'] = related_object.id
        
        return cls.objects.create(**log_data)
    
    @staticmethod
    def get_client_ip(request):
        """获取客户端IP地址"""
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip
    
    def get_change_summary(self):
        """获取变更摘要"""
        if not self.old_value or not self.new_value:
            return self.description
        
        changes = []
        for key, new_val in self.new_value.items():
            old_val = self.old_value.get(key)
            if old_val != new_val:
                changes.append(f"{key}: {old_val} → {new_val}")
        
        return "; ".join(changes) if changes else self.description

    def get_change_pairs(self):
        """以中文标签返回变更前后值对，用于详情展示
        返回列表：[{'field': '字段', 'old': '旧值', 'new': '新值'}]
        """
        if not self.new_value:
            return []

        label_map = {
            'name': '名称',
            'asset_number': '资产编号',
            'status': '状态',
            'location': '位置',
            'department': '部门',
            'department_id': '所属部门',
            'user': '使用人',
            'user_id': '使用人',
            'supplier': '供应商',
            'contract': '合同',
            'purchase_date': '采购日期',
            'purchase_price': '采购价格',
            'warranty_period': '保修期(月)',
            'depreciation_rate': '折旧率(%)',
            'description': '描述',
        }

        def _resolve_fk(key, v):
            """将外键ID转为名称（仅针对已知字段）"""
            if v in (None, ""):
                return v
            try:
                if key == 'user_id':
                    from django.contrib.auth.models import User as DjangoUser
                    # 兼容数字或字符串
                    uid = int(v)
                    u = DjangoUser.objects.filter(pk=uid).first()
                    if u:
                        return u.get_full_name() or u.username
                if key == 'department_id':
                    did = int(v)
                    d = Department.objects.filter(pk=did).first()
                    if d:
                        return d.name
            except Exception:
                # 忽略解析失败，回退原值
                return v
            return v

        def _fmt_value(key, v):
            from decimal import Decimal
            import datetime
            # 先尝试外键翻译
            rv = _resolve_fk(key, v)
            v = rv
            if isinstance(v, (list, dict)):
                import json
                return json.dumps(v, ensure_ascii=False)
            if isinstance(v, Decimal):
                return str(v)
            if isinstance(v, (datetime.date, datetime.datetime)):
                return v.strftime('%Y-%m-%d %H:%M:%S') if isinstance(v, datetime.datetime) else v.strftime('%Y-%m-%d')
            return '-' if v is None or v == '' else str(v)

        pairs = []
        old = self.old_value or {}
        for key, new_val in self.new_value.items():
            old_val = old.get(key)
            if old_val == new_val:
                continue
            pairs.append({
                'field': label_map.get(key, key),
                'old': _fmt_value(key, old_val),
                'new': _fmt_value(key, new_val),
            })
        return pairs


class Warehouse(models.Model):
    """仓库模型"""
    name = models.CharField(max_length=100, verbose_name="仓库名称")
    location = models.ForeignKey(Location, on_delete=models.CASCADE, verbose_name="位置", db_index=True)
    manager = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="管理员")
    description = models.TextField(blank=True, verbose_name="描述")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "仓库"
        verbose_name_plural = "仓库"
        constraints = [
            models.UniqueConstraint(fields=['name', 'location'], 
                                  name='unique_warehouse_location')
        ]
    
    def __str__(self):
        return self.name


class Consumable(models.Model):
    """耗材模型"""
    name = models.CharField(max_length=200, verbose_name="耗材名称")
    code = models.CharField(max_length=100, unique=True, verbose_name="耗材编码")
    model = models.CharField(max_length=100, blank=True, verbose_name="型号规格")
    category = models.ForeignKey(AssetCategory, on_delete=models.CASCADE, verbose_name="耗材类别")
    warehouse = models.ForeignKey(Warehouse, on_delete=models.CASCADE, verbose_name="所属仓库")
    unit = models.CharField(max_length=20, verbose_name="单位")  # 如：个、件、米等
    quantity = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="数量")
    min_quantity = models.DecimalField(max_digits=10, decimal_places=2, default=0, verbose_name="最低库存")
    purchase_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="采购单价")
    supplier = models.ForeignKey(Supplier, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="供应商")
    description = models.TextField(blank=True, verbose_name="描述")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "耗材"
        verbose_name_plural = "耗材"
    
    def __str__(self):
        return self.name


class InventoryLog(models.Model):
    """库存记录模型"""
    TRANSACTION_TYPE_CHOICES = [
        ('in', '入库'),
        ('out', '出库'),
    ]
    
    transaction_type = models.CharField(max_length=10, choices=TRANSACTION_TYPE_CHOICES, verbose_name="操作类型")
    consumable = models.ForeignKey(Consumable, on_delete=models.CASCADE, verbose_name="耗材")
    quantity = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="数量")
    remaining_quantity = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name="库存余额")
    operator = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, verbose_name="操作人")
    description = models.TextField(blank=True, verbose_name="描述")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="操作时间")
    
    class Meta:
        verbose_name = "库存记录"
        verbose_name_plural = "库存记录"
        ordering = ['-created_at']
    
    def __str__(self):
        return f"{self.get_transaction_type_display()} - {self.consumable.name}"


class MaintenanceRecord(models.Model):
    """资产维修记录模型"""
    MAINTENANCE_TYPE_CHOICES = [
        ('preventive', '预防性维修'),
        ('corrective', '纠正性维修'),
        ('emergency', '紧急维修'),
        ('upgrade', '升级改造'),
    ]
    
    MAINTENANCE_STATUS_CHOICES = [
        ('pending', '待处理'),
        ('in_progress', '维修中'),
        ('completed', '已完成'),
        ('cancelled', '已取消'),
    ]
    
    PRIORITY_CHOICES = [
        ('low', '低'),
        ('medium', '中'),
        ('high', '高'),
        ('urgent', '紧急'),
    ]
    
    asset = models.ForeignKey(Asset, on_delete=models.CASCADE, verbose_name="资产", related_name='maintenance_records')
    maintenance_type = models.CharField(max_length=20, choices=MAINTENANCE_TYPE_CHOICES, verbose_name="维修类型")
    status = models.CharField(max_length=20, choices=MAINTENANCE_STATUS_CHOICES, default='pending', verbose_name="维修状态")
    priority = models.CharField(max_length=10, choices=PRIORITY_CHOICES, default='medium', verbose_name="优先级")
    
    # 维修信息
    title = models.CharField(max_length=200, verbose_name="维修标题")
    description = models.TextField(verbose_name="问题描述")
    solution = models.TextField(blank=True, verbose_name="解决方案")
    
    # 时间信息
    reported_at = models.DateTimeField(auto_now_add=True, verbose_name="报告时间")
    scheduled_at = models.DateTimeField(null=True, blank=True, verbose_name="计划维修时间")
    started_at = models.DateTimeField(null=True, blank=True, verbose_name="开始维修时间")
    completed_at = models.DateTimeField(null=True, blank=True, verbose_name="完成时间")
    
    # 人员信息
    reporter = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='reported_maintenances', verbose_name="报告人")
    technician = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='assigned_maintenances', verbose_name="维修技师")
    
    # 成本信息
    estimated_cost = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name="预估成本")
    actual_cost = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name="实际成本")
    
    # 供应商信息
    supplier = models.ForeignKey(Supplier, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="维修供应商")
    
    # 备注
    notes = models.TextField(blank=True, verbose_name="备注")
    
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "维修记录"
        verbose_name_plural = "维修记录"
        ordering = ['-created_at']
    
    def __str__(self):
        return f"{self.asset.name} - {self.title}"
    
    @property
    def duration_hours(self):
        """计算维修时长（小时）"""
        if self.started_at and self.completed_at:
            duration = self.completed_at - self.started_at
            return round(duration.total_seconds() / 3600, 2)
        return None
    
    @property
    def is_overdue(self):
        """判断是否超期"""
        if self.scheduled_at and self.status in ['pending', 'in_progress']:
            from django.utils import timezone
            return timezone.now() > self.scheduled_at
        return False


class InventoryPlan(models.Model):
    """资产盘点计划模型"""
    PLAN_STATUS_CHOICES = [
        ('draft', '草稿'),
        ('active', '执行中'),
        ('completed', '已完成'),
        ('cancelled', '已取消'),
    ]
    
    PLAN_TYPE_CHOICES = [
        ('full', '全面盘点'),
        ('partial', '部分盘点'),
        ('spot_check', '抽查盘点'),
    ]
    
    name = models.CharField(max_length=200, verbose_name="盘点计划名称")
    plan_type = models.CharField(max_length=20, choices=PLAN_TYPE_CHOICES, verbose_name="盘点类型")
    status = models.CharField(max_length=20, choices=PLAN_STATUS_CHOICES, default='draft', verbose_name="计划状态")
    
    # 盘点范围
    departments = models.ManyToManyField(Department, blank=True, verbose_name="盘点部门")
    categories = models.ManyToManyField(AssetCategory, blank=True, verbose_name="盘点类别")
    locations = models.ManyToManyField(Location, blank=True, verbose_name="盘点位置")
    
    # 时间信息
    planned_start_date = models.DateTimeField(verbose_name="计划开始时间")
    planned_end_date = models.DateTimeField(verbose_name="计划结束时间")
    actual_start_date = models.DateTimeField(null=True, blank=True, verbose_name="实际开始时间")
    actual_end_date = models.DateTimeField(null=True, blank=True, verbose_name="实际结束时间")
    
    # 人员信息
    creator = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='created_inventory_plans', verbose_name="创建人")
    assignees = models.ManyToManyField(User, related_name='assigned_inventory_plans', verbose_name="盘点人员")
    
    # 描述信息
    description = models.TextField(blank=True, verbose_name="计划描述")
    notes = models.TextField(blank=True, verbose_name="备注")
    
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "盘点计划"
        verbose_name_plural = "盘点计划"
        ordering = ['-created_at']
    
    def __str__(self):
        return self.name
    
    @property
    def progress_percentage(self):
        """计算盘点进度百分比"""
        total_items = self.inventory_items.count()
        if total_items == 0:
            return 0
        completed_items = self.inventory_items.filter(status='completed').count()
        return round((completed_items / total_items) * 100, 2)
    
    @property
    def total_assets_count(self):
        """获取计划中的资产总数"""
        return self.inventory_items.count()
    
    @property
    def completed_assets_count(self):
        """获取已完成盘点的资产数量"""
        return self.inventory_items.filter(status='completed').count()
    
    @property
    def discrepancy_count(self):
        """获取存在差异的资产数量"""
        return self.inventory_items.filter(
            models.Q(physical_status__isnull=False) & 
            ~models.Q(physical_status=models.F('asset__status'))
        ).count()


class InventoryItem(models.Model):
    """盘点项目模型"""
    ITEM_STATUS_CHOICES = [
        ('pending', '待盘点'),
        ('in_progress', '盘点中'),
        ('completed', '已完成'),
        ('exception', '异常'),
    ]
    
    DISCREPANCY_TYPE_CHOICES = [
        ('none', '无差异'),
        ('status_mismatch', '状态不符'),
        ('location_mismatch', '位置不符'),
        ('user_mismatch', '使用人不符'),
        ('missing', '资产丢失'),
        ('found_extra', '发现额外资产'),
        ('damaged', '资产损坏'),
    ]
    
    plan = models.ForeignKey(InventoryPlan, on_delete=models.CASCADE, related_name='inventory_items', verbose_name="盘点计划")
    asset = models.ForeignKey(Asset, on_delete=models.CASCADE, verbose_name="资产")
    status = models.CharField(max_length=20, choices=ITEM_STATUS_CHOICES, default='pending', verbose_name="盘点状态")
    
    # 盘点人员
    assigned_to = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='assigned_inventory_items', verbose_name="分配给")
    checked_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='checked_inventory_items', verbose_name="盘点人")
    
    # 盘点时间
    assigned_at = models.DateTimeField(null=True, blank=True, verbose_name="分配时间")
    checked_at = models.DateTimeField(null=True, blank=True, verbose_name="盘点时间")
    
    # 系统记录信息（盘点时的系统记录）
    system_status = models.CharField(max_length=20, verbose_name="系统状态")
    system_location = models.ForeignKey(Location, on_delete=models.SET_NULL, null=True, blank=True, related_name='system_inventory_items', verbose_name="系统位置")
    system_user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='system_inventory_items', verbose_name="系统使用人")
    system_department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True, blank=True, related_name='system_inventory_items', verbose_name="系统部门")
    
    # 实际盘点信息
    physical_status = models.CharField(max_length=20, blank=True, verbose_name="实际状态")
    physical_location = models.ForeignKey(Location, on_delete=models.SET_NULL, null=True, blank=True, related_name='physical_inventory_items', verbose_name="实际位置")
    physical_user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='physical_inventory_items', verbose_name="实际使用人")
    physical_department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True, blank=True, related_name='physical_inventory_items', verbose_name="实际部门")
    
    # 差异信息
    discrepancy_type = models.CharField(max_length=20, choices=DISCREPANCY_TYPE_CHOICES, default='none', verbose_name="差异类型")
    discrepancy_notes = models.TextField(blank=True, verbose_name="差异说明")
    
    # 处理信息
    resolution_action = models.TextField(blank=True, verbose_name="处理措施")
    resolved_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='resolved_inventory_items', verbose_name="处理人")
    resolved_at = models.DateTimeField(null=True, blank=True, verbose_name="处理时间")
    
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "盘点项目"
        verbose_name_plural = "盘点项目"
        unique_together = ['plan', 'asset']
        ordering = ['asset__asset_number']
    
    def __str__(self):
        return f"{self.plan.name} - {self.asset.name}"
    
    def detect_discrepancies(self):
        """检测并记录差异"""
        discrepancies = []
        
        # 检查状态差异
        if self.physical_status and self.physical_status != self.system_status:
            discrepancies.append({
                'type': 'status_mismatch',
                'field': '状态',
                'system_value': self.get_system_status_display(),
                'physical_value': self.get_physical_status_display(),
                'description': f'系统状态为"{self.get_system_status_display()}"，实际状态为"{self.get_physical_status_display()}"'
            })
        
        # 检查位置差异
        if self.physical_location != self.system_location:
            system_location = self.system_location.name if self.system_location else '未设置'
            physical_location = self.physical_location.name if self.physical_location else '未设置'
            if system_location != physical_location:
                discrepancies.append({
                    'type': 'location_mismatch',
                    'field': '位置',
                    'system_value': system_location,
                    'physical_value': physical_location,
                    'description': f'系统位置为"{system_location}"，实际位置为"{physical_location}"'
                })
        
        # 检查使用人差异
        if self.physical_user != self.system_user:
            system_user = self.system_user.username if self.system_user else '未分配'
            physical_user = self.physical_user.username if self.physical_user else '未分配'
            if system_user != physical_user:
                discrepancies.append({
                    'type': 'user_mismatch',
                    'field': '使用人',
                    'system_value': system_user,
                    'physical_value': physical_user,
                    'description': f'系统使用人为"{system_user}"，实际使用人为"{physical_user}"'
                })
        
        # 检查部门差异
        if self.physical_department != self.system_department:
            system_dept = self.system_department.name if self.system_department else '未分配'
            physical_dept = self.physical_department.name if self.physical_department else '未分配'
            if system_dept != physical_dept:
                discrepancies.append({
                    'type': 'department_mismatch',
                    'field': '部门',
                    'system_value': system_dept,
                    'physical_value': physical_dept,
                    'description': f'系统部门为"{system_dept}"，实际部门为"{physical_dept}"'
                })
        
        # 更新差异类型和说明
        if discrepancies:
            # 设置主要差异类型（取第一个差异的类型）
            self.discrepancy_type = discrepancies[0]['type']
            
            # 生成差异说明
            descriptions = [d['description'] for d in discrepancies]
            self.discrepancy_notes = '; '.join(descriptions)
        else:
            self.discrepancy_type = 'none'
            self.discrepancy_notes = ''
        
        return discrepancies
    
    def get_system_status_display(self):
        """获取系统状态的显示名称"""
        status_dict = dict(Asset.ASSET_STATUS_CHOICES)
        return status_dict.get(self.system_status, self.system_status)
    
    def get_physical_status_display(self):
        """获取实际状态的显示名称"""
        if not self.physical_status:
            return '未盘点'
        status_dict = dict(Asset.ASSET_STATUS_CHOICES)
        return status_dict.get(self.physical_status, self.physical_status)
    
    def has_discrepancies(self):
        """判断是否存在差异"""
        return self.discrepancy_type != 'none'
    
    def complete_check(self, user, physical_data):
        """完成盘点检查"""
        from django.utils import timezone
        
        # 更新实际盘点信息
        self.physical_status = physical_data.get('physical_status', '')
        self.physical_location_id = physical_data.get('physical_location')
        self.physical_user_id = physical_data.get('physical_user')
        self.physical_department_id = physical_data.get('physical_department')
        
        # 设置盘点人和时间
        self.checked_by = user
        self.checked_at = timezone.now()
        
        # 检测差异
        discrepancies = self.detect_discrepancies()
        
        # 更新状态
        if discrepancies:
            self.status = 'exception'
        else:
            self.status = 'completed'
        
        self.save()
        
        # 记录操作日志
        AssetLog.log_action(
            asset=self.asset,
            action='inventory',
            operator=user,
            description=f'完成盘点 - {self.plan.name}',
            old_value={
                'status': self.system_status,
                'location': self.system_location.name if self.system_location else None,
                'user': self.system_user.username if self.system_user else None,
                'department': self.system_department.name if self.system_department else None,
            },
            new_value={
                'status': self.physical_status,
                'location': self.physical_location.name if self.physical_location else None,
                'user': self.physical_user.username if self.physical_user else None,
                'department': self.physical_department.name if self.physical_department else None,
            },
            related_object=self
        )
        
        return discrepancies


class AssetBorrow(models.Model):
    """资产借用记录模型"""
    BORROW_STATUS_CHOICES = [
        ('pending', '待审批'),
        ('approved', '已审批'),
        ('rejected', '已拒绝'),
        ('borrowed', '已借出'),
        ('returned', '已归还'),
        ('overdue', '已逾期'),
        ('cancelled', '已取消'),
    ]
    
    BORROW_PURPOSE_CHOICES = [
        ('work', '工作使用'),
        ('meeting', '会议使用'),
        ('training', '培训使用'),
        ('project', '项目使用'),
        ('maintenance', '维修使用'),
        ('other', '其他'),
    ]
    
    # 基本信息
    asset = models.ForeignKey(Asset, on_delete=models.CASCADE, verbose_name="资产", related_name='borrow_records')
    borrower = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="借用人", related_name='borrowed_assets')
    borrower_department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="借用部门")
    
    # 借用信息
    purpose = models.CharField(max_length=20, choices=BORROW_PURPOSE_CHOICES, verbose_name="借用目的")
    purpose_description = models.TextField(verbose_name="借用说明")
    expected_return_date = models.DateTimeField(verbose_name="预计归还时间")
    
    # 状态信息
    status = models.CharField(max_length=20, choices=BORROW_STATUS_CHOICES, default='pending', verbose_name="借用状态")
    
    # 审批信息
    approver = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="审批人", related_name='approved_borrows')
    approved_at = models.DateTimeField(null=True, blank=True, verbose_name="审批时间")
    approval_notes = models.TextField(blank=True, verbose_name="审批备注")
    
    # 借出信息
    borrowed_at = models.DateTimeField(null=True, blank=True, verbose_name="实际借出时间")
    borrowed_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="办理借出人", related_name='handled_borrows')
    
    # 归还信息
    actual_return_date = models.DateTimeField(null=True, blank=True, verbose_name="实际归还时间")
    returned_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="办理归还人", related_name='handled_returns')
    return_condition = models.TextField(blank=True, verbose_name="归还时资产状态")
    return_notes = models.TextField(blank=True, verbose_name="归还备注")
    
    # 联系信息
    contact_phone = models.CharField(max_length=20, blank=True, verbose_name="联系电话")
    contact_email = models.EmailField(blank=True, verbose_name="联系邮箱")
    
    # 时间戳
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "资产借用记录"
        verbose_name_plural = "资产借用记录"
        ordering = ['-created_at']
    
    def __str__(self):
        return f"{self.asset.name} - {self.borrower.get_full_name() or self.borrower.username}"
    
    @property
    def is_overdue(self):
        """是否逾期"""
        if self.status == 'borrowed' and self.expected_return_date:
            from django.utils import timezone
            return timezone.now() > self.expected_return_date
        return False
    
    @property
    def days_overdue(self):
        """逾期天数"""
        if self.is_overdue:
            from django.utils import timezone
            delta = timezone.now() - self.expected_return_date
            return delta.days
        return 0
    
    @property
    def borrow_duration(self):
        """借用时长（天）"""
        if self.borrowed_at and self.actual_return_date:
            delta = self.actual_return_date - self.borrowed_at
            return delta.days
        elif self.borrowed_at:
            from django.utils import timezone
            delta = timezone.now() - self.borrowed_at
            return delta.days
        return 0
    
    @property
    def can_approve(self):
        """是否可以审批"""
        return self.status == 'pending'
    
    @property
    def can_borrow(self):
        """是否可以借出"""
        return self.status == 'approved'
    
    @property
    def can_return(self):
        """是否可以归还"""
        return self.status in ['borrowed', 'overdue']
    
    @property
    def can_cancel(self):
        """是否可以取消"""
        return self.status in ['pending', 'approved']
    
    def approve(self, approver, notes=''):
        """审批通过"""
        if self.can_approve:
            from django.utils import timezone
            self.status = 'approved'
            self.approver = approver
            self.approved_at = timezone.now()
            self.approval_notes = notes
            self.save()
            return True
        return False
    
    def reject(self, approver, notes=''):
        """审批拒绝"""
        if self.can_approve:
            from django.utils import timezone
            self.status = 'rejected'
            self.approver = approver
            self.approved_at = timezone.now()
            self.approval_notes = notes
            self.save()
            return True
        return False
    
    def borrow_out(self, handler):
        """办理借出"""
        if self.can_borrow:
            from django.utils import timezone
            self.status = 'borrowed'
            self.borrowed_at = timezone.now()
            self.borrowed_by = handler
            # 更新资产状态
            self.asset.status = 'borrowed'
            self.asset.user = self.borrower
            self.asset.save()
            self.save()
            return True
        return False
    
    def return_asset(self, handler, condition='', notes=''):
        """办理归还"""
        if self.can_return:
            from django.utils import timezone
            self.status = 'returned'
            self.actual_return_date = timezone.now()
            self.returned_by = handler
            self.return_condition = condition
            self.return_notes = notes
            # 恢复资产状态
            self.asset.status = 'idle'
            self.asset.user = None
            self.asset.save()
            self.save()
            return True
        return False
    
    def cancel(self):
        """取消借用"""
        if self.can_cancel:
            self.status = 'cancelled'
            self.save()
            return True
        return False
    
    def update_overdue_status(self):
        """更新逾期状态"""
        if self.is_overdue and self.status == 'borrowed':
            self.status = 'overdue'
            self.save()
            return True
        return False
    
    @property
    def has_discrepancy(self):
        """判断是否存在差异"""
        return self.discrepancy_type != 'none'
    
    def detect_discrepancies(self):
        """自动检测差异"""
        discrepancies = []
        
        # 检查状态差异
        if self.physical_status and self.physical_status != self.system_status:
            discrepancies.append('status_mismatch')
        
        # 检查位置差异
        if self.physical_location and self.physical_location != self.system_location:
            discrepancies.append('location_mismatch')
        
        # 检查使用人差异
        if self.physical_user and self.physical_user != self.system_user:
            discrepancies.append('user_mismatch')
        
        # 检查部门差异
        if self.physical_department and self.physical_department != self.system_department:
            discrepancies.append('department_mismatch')
        
        if discrepancies:
            self.discrepancy_type = discrepancies[0]  # 取第一个发现的差异
        else:
            self.discrepancy_type = 'none'
        
        return discrepancies


class InventoryAlert(models.Model):
    """库存预警模型"""
    ALERT_TYPE_CHOICES = [
        ('low_stock', '低库存预警'),
        ('out_of_stock', '缺货预警'),
        ('expiry_warning', '过期预警'),
        ('reorder_point', '补货提醒'),
    ]
    
    ALERT_STATUS_CHOICES = [
        ('active', '活跃'),
        ('acknowledged', '已确认'),
        ('resolved', '已解决'),
        ('ignored', '已忽略'),
    ]
    
    PRIORITY_CHOICES = [
        ('low', '低'),
        ('medium', '中'),
        ('high', '高'),
        ('urgent', '紧急'),
    ]
    
    consumable = models.ForeignKey(Consumable, on_delete=models.CASCADE, verbose_name="相关耗材", related_name='alerts')
    alert_type = models.CharField(max_length=20, choices=ALERT_TYPE_CHOICES, verbose_name="预警类型")
    status = models.CharField(max_length=20, choices=ALERT_STATUS_CHOICES, default='active', verbose_name="预警状态")
    priority = models.CharField(max_length=10, choices=PRIORITY_CHOICES, default='medium', verbose_name="优先级")
    
    current_quantity = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="当前库存")
    threshold_quantity = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="预警阈值")
    suggested_order_quantity = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name="建议订购量")
    
    message = models.TextField(verbose_name="预警消息")
    acknowledged_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='acknowledged_alerts', verbose_name="确认人")
    acknowledged_at = models.DateTimeField(null=True, blank=True, verbose_name="确认时间")
    resolved_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='resolved_alerts', verbose_name="解决人")
    resolved_at = models.DateTimeField(null=True, blank=True, verbose_name="解决时间")
    
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    
    class Meta:
        verbose_name = "库存预警"
        verbose_name_plural = "库存预警"
        ordering = ['-created_at']
    
    def __str__(self):
        return f"{self.consumable.name} - {self.get_alert_type_display()}"
    
    @property
    def is_active(self):
        """是否为活跃预警"""
        return self.status == 'active'
    
    @property
    def is_urgent(self):
        """是否为紧急预警"""
        return self.priority == 'urgent' or self.alert_type == 'out_of_stock'
    
    @property
    def days_since_created(self):
        """创建以来的天数"""
        from django.utils import timezone
        delta = timezone.now() - self.created_at
        return delta.days
    
    def acknowledge(self, user):
        """确认预警"""
        if self.status == 'active':
            from django.utils import timezone
            self.status = 'acknowledged'
            self.acknowledged_by = user
            self.acknowledged_at = timezone.now()
            self.save()
            return True
        return False
    
    def resolve(self, user):
        """解决预警"""
        if self.status in ['active', 'acknowledged']:
            from django.utils import timezone
            self.status = 'resolved'
            self.resolved_by = user
            self.resolved_at = timezone.now()
            self.save()
            return True
        return False
    
    def ignore(self):
        """忽略预警"""
        if self.status == 'active':
            self.status = 'ignored'
            self.save()
            return True
        return False
    
    @classmethod
    def generate_low_stock_alerts(cls):
        """生成低库存预警"""
        from django.db.models import Q
        
        # 查找库存低于最低库存的耗材
        low_stock_consumables = Consumable.objects.filter(
            quantity__lte=models.F('min_quantity'),
            quantity__gt=0
        ).exclude(
            alerts__alert_type='low_stock',
            alerts__status='active'
        )
        
        alerts_created = 0
        for consumable in low_stock_consumables:
            from decimal import Decimal
            # 计算建议订购量（最低库存的2倍减去当前库存）
            suggested_quantity = max(0, consumable.min_quantity * 2 - consumable.quantity)
            
            # 确定优先级
            if consumable.quantity <= consumable.min_quantity * Decimal('0.5'):
                priority = 'urgent'
            elif consumable.quantity <= consumable.min_quantity * Decimal('0.8'):
                priority = 'high'
            else:
                priority = 'medium'
            
            message = f"耗材 '{consumable.name}' 库存不足。当前库存：{consumable.quantity} {consumable.unit}，最低库存：{consumable.min_quantity} {consumable.unit}"
            
            cls.objects.create(
                consumable=consumable,
                alert_type='low_stock',
                priority=priority,
                current_quantity=consumable.quantity,
                threshold_quantity=consumable.min_quantity,
                suggested_order_quantity=suggested_quantity,
                message=message
            )
            alerts_created += 1
        
        return alerts_created
    
    @classmethod
    def generate_out_of_stock_alerts(cls):
        """生成缺货预警"""
        # 查找库存为0的耗材
        out_of_stock_consumables = Consumable.objects.filter(
            quantity=0
        ).exclude(
            alerts__alert_type='out_of_stock',
            alerts__status='active'
        )
        
        alerts_created = 0
        for consumable in out_of_stock_consumables:
            # 建议订购量为最低库存的2倍
            suggested_quantity = consumable.min_quantity * 2
            
            message = f"耗材 '{consumable.name}' 已缺货！当前库存：0 {consumable.unit}，建议立即补货。"
            
            cls.objects.create(
                consumable=consumable,
                alert_type='out_of_stock',
                priority='urgent',
                current_quantity=0,
                threshold_quantity=consumable.min_quantity,
                suggested_order_quantity=suggested_quantity,
                message=message
            )
            alerts_created += 1
        
        return alerts_created
    
    @classmethod
    def generate_reorder_alerts(cls):
        """生成补货提醒"""
        from django.db.models import Q
        from django.utils import timezone
        from datetime import timedelta
        
        # 查找库存接近最低库存且最近没有补货提醒的耗材
        from decimal import Decimal
        reorder_threshold = Decimal('1.2')  # 120%的最低库存作为补货提醒阈值
        
        reorder_consumables = Consumable.objects.filter(
            quantity__lte=models.F('min_quantity') * reorder_threshold,
            quantity__gt=models.F('min_quantity')
        ).exclude(
            Q(alerts__alert_type='reorder_point', alerts__status='active') |
            Q(alerts__alert_type='reorder_point', alerts__created_at__gte=timezone.now() - timedelta(days=7))
        )
        
        alerts_created = 0
        for consumable in reorder_consumables:
            suggested_quantity = consumable.min_quantity * Decimal('1.5')
            
            message = f"耗材 '{consumable.name}' 建议补货。当前库存：{consumable.quantity} {consumable.unit}，建议在库存进一步降低前补货。"
            
            cls.objects.create(
                consumable=consumable,
                alert_type='reorder_point',
                priority='low',
                current_quantity=consumable.quantity,
                threshold_quantity=consumable.min_quantity * reorder_threshold,
                suggested_order_quantity=suggested_quantity,
                message=message
            )
            alerts_created += 1
        
        return alerts_created
    
    @classmethod
    def cleanup_resolved_alerts(cls, days=30):
        """清理已解决的旧预警"""
        from django.utils import timezone
        from datetime import timedelta
        
        cutoff_date = timezone.now() - timedelta(days=days)
        deleted_count = cls.objects.filter(
            status__in=['resolved', 'ignored'],
            updated_at__lt=cutoff_date
        ).delete()[0]
        
        return deleted_count


# 为Consumable模型添加库存预警相关方法
def get_current_alert_level(self):
    """获取当前预警级别"""
    from decimal import Decimal
    
    if self.quantity <= 0:
        return 'out_of_stock'
    elif self.quantity <= self.min_quantity:
        return 'low_stock'
    elif self.quantity <= self.min_quantity * Decimal('1.2'):
        return 'reorder_point'
    else:
        return 'normal'

def get_stock_status_color(self):
    """获取库存状态颜色"""
    level = self.get_current_alert_level()
    colors = {
        'out_of_stock': 'danger',
        'low_stock': 'warning',
        'reorder_point': 'info',
        'normal': 'success'
    }
    return colors.get(level, 'secondary')

def get_stock_percentage(self):
    """获取库存百分比（相对于最低库存）"""
    if self.min_quantity > 0:
        return min(100, (float(self.quantity) / float(self.min_quantity)) * 100)
    return 100 if self.quantity > 0 else 0

def needs_reorder(self):
    """是否需要补货"""
    from decimal import Decimal
    return self.quantity <= self.min_quantity * Decimal('1.2')

def is_critical_stock(self):
    """是否为紧急库存状态"""
    return self.quantity <= self.min_quantity * 0.5

def get_suggested_order_quantity(self):
    """获取建议订购量"""
    if self.quantity <= 0:
        return self.min_quantity * 2
    elif self.quantity <= self.min_quantity:
        return max(0, self.min_quantity * 2 - self.quantity)
    else:
        return self.min_quantity

# 将方法添加到Consumable类
Consumable.get_current_alert_level = get_current_alert_level
Consumable.get_stock_status_color = get_stock_status_color
Consumable.get_stock_percentage = get_stock_percentage
Consumable.needs_reorder = needs_reorder
Consumable.is_critical_stock = is_critical_stock
Consumable.get_suggested_order_quantity = get_suggested_order_quantity
# 导入扩展模型
from .models_system import *
from .models_transfer import *
from .models_workflow import *
from .models_ai import *
from .models_search import *